package system_admin

import (
	"context"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"system-admin/config"
	"system-admin/config/mysql"
	"system-admin/internal/app/grpc/protoc/system_admin"
	"system-admin/internal/app/web/service/file"
	"system-admin/internal/app/web/service/merchant"
	"system-admin/internal/app/web/service/user"
	"system-admin/internal/dal"
	"system-admin/internal/dao"
	"system-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"192.168.1.75/go-pkg/timewheel"
	"github.com/samber/lo"
)

var removeExpiredFileTimeWheel *timewheel.TimeWheel

// 时间轮初始化
func init() {
	// 过期文件的检查及删除
	removeExpiredFileTimeWheel = timewheel.New(time.Second, 60, func(val interface{}) {
		if saveDir, ok := val.(string); ok {
			diffTime := int64(1800)      // 超时时间为半个小时
			nowTime := time.Now().Unix() // 当前时间，使用Unix时间戳
			_ = filepath.Walk(saveDir, func(path string, fi os.FileInfo, err error) error {
				if !fi.IsDir() {
					fileTime := fi.ModTime().Unix()
					if (nowTime - fileTime) > diffTime { // 判断文件是否过期
						os.Remove(path)
					}
				}
				return nil
			})
		}
	})
	removeExpiredFileTimeWheel.Start()
}

type Server struct {
	system_admin.UnimplementedBaseServiceServer
}

// AreaList 区域列表
func (Server) AreaList(ctx context.Context, req *system_admin.AreaLisRequest) (*system_admin.AreaListResponse, error) {
	// 从数据库查询记录
	var areas []models.Area
	tx := mysql.NewDB().Model(&models.Area{})
	// 查询条件
	if len(req.AreaIDs) > 0 {
		tx = tx.Where("id IN ?", req.AreaIDs)
	}
	level := req.Level
	if level > 3 || level <= 0 {
		level = 3
	}
	tx.Where("level <= ?", level)
	tx.Find(&areas)
	// 结果转protobuf格式
	res := &system_admin.AreaListResponse{}
	for _, area := range areas {
		res.Areas = append(res.Areas, &system_admin.AreaListResponseArea{
			ID:       area.ID,
			Name:     area.Name,
			Level:    int32(area.Level),
			ParentID: area.ParentID,
		})
	}

	return res, nil
}

// MerchantInfo 商户信息
func (Server) MerchantInfo(ctx context.Context, req *system_admin.MerchantInfoReq) (*system_admin.MerchantInfoRsp, error) {
	merchantDetail, err := merchant.MerchantDetail(req.MerchantId)
	merchantInfo := &system_admin.MerchantInfoRsp{}
	if err != nil {
		merchantInfo.Code = -1
		merchantInfo.Msg = "商户不存在"
	} else {
		merchantInfo.MerchantName = merchantDetail.Name
		merchantInfo.MerchantPath = merchantDetail.MerchantPath
		merchantInfo.MerchantApiToken = merchantDetail.APIToken
	}
	return merchantInfo, nil
}

// MerchantList 商户列表
func (Server) MerchantList(ctx context.Context, req *system_admin.MerchantListReq) (*system_admin.MerchantListRsp, error) {
	allMerchant, total := merchant.AllMerchant(req.UserId, req.MerchantId, "id,name,merchant_path", int(req.Page), int(req.Limit))
	rsp := &system_admin.MerchantListRsp{}
	rsp.Total = total
	for _, merchant := range allMerchant {
		rsp.List = append(rsp.List, &system_admin.MerchantListRspMerchant{
			MerchantId:   merchant.ID,
			MerchantName: merchant.Name,
			MerchantPath: merchant.MerchantPath,
		})
	}
	return rsp, nil
}

// ConfirmFile 文件确认
func (Server) ConfirmFile(ctx context.Context, req *system_admin.ConfirmFileReq) (*system_admin.ConfirmFileRsp, error) {
	fileURL, err := file.ConfirmFile(req.FileUrl)
	rsp := &system_admin.ConfirmFileRsp{}
	if err != nil {
		rsp.Code = -1
		rsp.Msg = err.Error()
	} else {
		rsp.FileUrl = fileURL
	}
	return rsp, nil
}

// ProvinceList 省份列表
func (Server) ProvinceList(ctx context.Context, req *system_admin.ProvinceListReq) (*system_admin.ProvinceListRsp, error) {
	var areas []models.Area
	tx := mysql.NewDB().Model(&models.Area{})
	tx.Where("level = ?", 1)
	tx.Find(&areas)
	res := &system_admin.ProvinceListRsp{}
	for _, area := range areas {
		res.Areas = append(res.Areas, &system_admin.Area{
			ID:   area.ID,
			Name: area.Name,
		})
	}
	return res, nil
}

// CityList 城市列表
func (Server) CityList(ctx context.Context, req *system_admin.CityListReq) (*system_admin.CityListRsp, error) {
	var areas []models.Area
	tx := mysql.NewDB().Model(&models.Area{})
	tx.Where("parent_id = ?", req.ProvinceId)
	tx.Find(&areas)
	res := &system_admin.CityListRsp{}
	for _, area := range areas {
		res.Areas = append(res.Areas, &system_admin.Area{
			ID:   area.ID,
			Name: area.Name,
		})
	}
	return res, nil
}

// DistrictList 区列表
func (Server) DistrictList(ctx context.Context, req *system_admin.DistrictListReq) (*system_admin.DistrictListRsp, error) {
	var areas []models.Area
	tx := mysql.NewDB().Model(&models.Area{})
	tx.Where("parent_id = ?", req.CityId)
	tx.Find(&areas)
	res := &system_admin.DistrictListRsp{}
	for _, area := range areas {
		res.Areas = append(res.Areas, &system_admin.Area{
			ID:   area.ID,
			Name: area.Name,
		})
	}
	return res, nil
}

// MerchantAPITokenInfo 商户apiToken信息
func (Server) MerchantAPITokenInfo(ctx context.Context, req *system_admin.MerchantAPITokenInfoReq) (*system_admin.MerchantAPITokenInfoRsp, error) {
	var merchant models.Merchant
	rowsAffected := mysql.NewDB().Model(&models.Merchant{}).
		Where("api_token = ?", req.MerchantApiToken).
		Take(&merchant).
		RowsAffected
	if rowsAffected <= 0 {
		return &system_admin.MerchantAPITokenInfoRsp{
			Code: -1,
			Msg:  "无效的token",
		}, nil
	}
	return &system_admin.MerchantAPITokenInfoRsp{
		Code:             0,
		MerchantId:       merchant.ID,
		MerchantName:     merchant.Name,
		MerchantPath:     merchant.MerchantPath,
		MerchantApiToken: merchant.APIToken,
	}, nil
}

// 用户登录
func (Server) UserLogin(ctx context.Context, req *system_admin.LoginReq) (*system_admin.LoginRsp, error) {
	token, err := user.LoginV2(req.Username, req.Password, req.CaptchaId, req.CaptchaCode)
	res := &system_admin.LoginRsp{}
	if err != nil {
		res.Code = -1
		res.Msg = err.Error()
	} else {
		res.Code = 0
		res.Data = &system_admin.LoginRsp_LoginReturnData{}
		res.Data.Token = token
	}
	return res, nil
}

// 文件上传
func (Server) FileUpload(ss system_admin.BaseService_FileUploadServer) (err error) {
	var res = &system_admin.FileUploadRsp{}
	fileContent := []byte{}
	// 接收处理
	for {
		select {
		// 会话结束
		case <-ss.Context().Done():
			fmt.Println("connect done")
			return
		default: //分段接收文件
			req, err1 := ss.Recv()
			// 消息处理
			if err1 == nil && req != nil {
				fileContent = append(fileContent, req.File...)
				if req.End == 1 {
					// 判断系统名称是否有效
					if !lo.Contains([]string{"system-admin", "device-admin", "sale-admin", "advertising", "mini-app"}, req.SystemName) {
						res.Code = -1
						res.Msg = "无效的系统名称"
						ss.Send(res)
						return
					}
					saveDir := path.Join(config.Config.FileSaveDir, req.SystemName, req.Dir, "temp")
					// 判断是否需要创建文件夹
					_, err2 := os.Stat(saveDir)
					if err2 != nil {
						err = os.MkdirAll(saveDir, os.ModePerm)
						if err != nil {
							res.Code = -1
							res.Msg = "创建文件夹失败"
							ss.Send(res)
							return
						}
					}
					primaryKey, err3 := helper.UUID{}.String()
					if err3 != nil {
						res.Code = -1
						res.Msg = "新建文件名失败"
						ss.Send(res)
						return
					}
					// 保存上传的文件
					tempFile := saveDir + "/" + primaryKey + "-" + req.FileName

					createFile, err4 := os.Create(tempFile)
					if err4 != nil {
						res.Code = -1
						res.Msg = "创建文件失败"
						ss.Send(res)
						return
					}
					defer createFile.Close()

					err = os.WriteFile(tempFile, fileContent, os.ModePerm)
					if err != nil {
						res.Code = -1
						res.Msg = "文件写入失败"
						ss.Send(res)
						return
					}
					res.FileUrl = tempFile
					// 延期检查删除过期的文件
					removeExpiredFileTimeWheel.AddTimer(primaryKey, time.Minute*30, saveDir)
					res.Code = 0
					res.Msg = "成功"
					ss.Send(res)
					return
				}
			} else {
				logx.Error(context.Background(), "file upload err", logx.Any("req", req), logx.Err(err1))
				return
			}
		}
	}
}

// DeleteFile 删除上传的文件
func (Server) DeleteFile(ctx context.Context, req *system_admin.DeleteFileReq) (*system_admin.DeleteFileRsp, error) {
	err := os.Remove(req.FileUrl)
	if err != nil {
		rsp := &system_admin.DeleteFileRsp{}
		rsp.Code = -1
		rsp.Msg = "删除文件失败"
		return rsp, nil
	}
	return nil, nil
}

// 商户列表带管理员信息
func (Server) MerchantListWithAdminUser(ctx context.Context, req *system_admin.MerchantListWithAdminUserReq) (*system_admin.MerchantListWithAdminUserRsp, error) {
	res := &system_admin.MerchantListWithAdminUserRsp{}
	db := mysql.NewDB()
	tx := db.Table(models.Merchant{}.TableName() + " as m").
		Joins("left join " + models.User{}.TableName() + " as user on user.id = m.admin_user_id").
		Where("m.deleted_at = 0")
	if req.Name != "" {
		tx.Where("m.name like (?)", "%"+req.Name+"%")
	}

	tx.Count(&res.Total)
	MerchantList := []struct {
		MerchantId    string `gorm:"column:merchant_id"`
		MerchantName  string `gorm:"column:merchant_name"`
		AdminUserId   string `gorm:"column:admin_user_id"`
		AdminUserName string `gorm:"column:admin_user_name"`
	}{}
	helper.Gorm{}.Paginate(tx, int(req.Page), int(req.Limit)).
		Select("m.id as merchant_id, m.name as merchant_name, m.admin_user_id, user.username as admin_user_name").
		Find(&MerchantList)
	for _, v := range MerchantList {
		item := &system_admin.MerchantListWithAdminUserRspMerchant{}
		item.MerchantId = v.MerchantId
		item.MerchantName = v.MerchantName
		item.AdminUserId = v.AdminUserId
		item.AdminUserName = v.AdminUserName
		res.List = append(res.List, item)
	}
	return res, nil
}

// UserList 用户列表
func (Server) UserList(ctx context.Context, req *system_admin.UserListReq) (*system_admin.UserListRsp, error) {
	merchnatID, _ := strconv.ParseInt(req.MerchantId, 10, 64)
	list, err := dao.User{}.UserList(ctx, dal.Q, merchnatID)
	if err != nil {
		return nil, err
	}
	rsp := &system_admin.UserListRsp{}
	rsp.Code = 0
	rsp.Total = int64(len(list))
	rsp.List = []*system_admin.UserListRspUser{}
	for _, user := range list {
		rsp.List = append(rsp.List, &system_admin.UserListRspUser{
			Id:       user.ID,
			Username: user.Username,
		})
	}
	return rsp, nil
}

// 获取直系商户
func (Server) GetFamilyMerchants(ctx context.Context, req *system_admin.FamilyMerchantsReq) (*system_admin.FamilyMerchantsRsp, error) {
	var merchantPrefix = ""
	merchantID := req.MerchantId
	merchantIDs := []string{}
	merchants := []models.Merchant{}
	var merchant models.Merchant
	mysql.NewDB().Model(&models.Merchant{}).Where("id = ?", merchantID).Take(&merchant)
	merchantPath := merchant.MerchantPath
	merchantArr := strings.Split(merchantPath, ">")
	// 系统用户没有直系商户
	if merchantID == "1" {
		return &system_admin.FamilyMerchantsRsp{
			MerchantIds: merchantIDs,
		}, nil
	} else if len(merchantArr) == 2 { // admin直属商户
		merchantPrefix = ">1>" + merchantID
	} else if len(merchantArr) > 2 { // admin直属下的商户
		merchantPrefix = ">1>" + merchantArr[2]
	}
	if merchantPrefix != "" {
		mysql.NewDB().Model(&models.Merchant{}).Where("merchant_path LIKE ?", merchantPrefix+"%").Find(&merchants)
	}
	for _, merchant := range merchants {
		merchantIDs = append(merchantIDs, merchant.ID)
	}
	// 包含当前商户
	merchantIDs = append(merchantIDs, merchantID)
	// 包含顶级商户
	if len(merchantArr) > 2 {
		merchantIDs = append(merchantIDs, merchantArr[2])
	}
	// 去重
	merchantIDs = lo.Uniq(merchantIDs)
	// 返回结果
	return &system_admin.FamilyMerchantsRsp{
		MerchantIds: merchantIDs,
	}, nil
}

// MerchantName 获取商户名称
func (Server) MerchantName(ctx context.Context, req *system_admin.MerchantNameReq) (*system_admin.MerchantNameRsp, error) {
	if len(req.MerchantIds) <= 0 {
		return nil, errorx.New("商户id不能为空", -1)
	}
	var records []models.Merchant
	mysql.NewDB().Model(&models.Merchant{}).Where("id IN ?", req.MerchantIds).Find(&records)
	merchantNameRsp := &system_admin.MerchantNameRsp{}
	merchantNameRsp.MerchantNameMap = map[string]string{}
	for _, record := range records {
		merchantNameRsp.MerchantNameMap[record.ID] = record.Name
	}
	merchantNameRsp.MerchantNameMap["1"] = "平台"
	return merchantNameRsp, nil
}

// UserName 获取用户名称
func (Server) UserName(ctx context.Context, req *system_admin.UserNameReq) (*system_admin.UserNameRsp, error) {
	if len(req.UserIds) <= 0 {
		return nil, errorx.New("用户id不能为空", -1)
	}
	var records []models.User
	mysql.NewDB().Model(&models.User{}).Where("id IN ?", req.UserIds).Find(&records)
	userNameRsp := &system_admin.UserNameRsp{}
	userNameRsp.UserNameMap = map[string]string{}
	for _, record := range records {
		userNameRsp.UserNameMap[record.ID] = record.Username
	}
	return userNameRsp, nil
}

// AreaName 获取地区名称
func (Server) AreaName(ctx context.Context, req *system_admin.AreaNameReq) (*system_admin.AreaNameRsp, error) {
	if len(req.AreaIds) <= 0 {
		return nil, errorx.New("区域id不能为空", -1)
	}
	var records []models.Area
	mysql.NewDB().Model(&models.Area{}).Where("id IN ?", req.AreaIds).Find(&records)
	areaNameRsp := &system_admin.AreaNameRsp{}
	areaNameRsp.AreaNameMap = make(map[string]string)
	for _, record := range records {
		areaNameRsp.AreaNameMap[record.ID] = record.Name
	}
	return areaNameRsp, nil
}
